/* 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Title : com.Angaliwa.Sidebar
Author : Dave Jansen -- Zenitum
URL : http://www.zenitum.com/

Description : Creates a sidebar with a virtually unlimited
			  amount of tabs. Tabs are created based on
			  Flex' TabBar module. Tabs can be placed on
			  any side of the sidebar. The sidebar
			  can be docked on any side of the window, or
			  can 'float'.

History		: v1.0.090727 Initial version

Created 	: July 27th, 2009

Version		: 1.0
Compatibility: 1.0

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
*/

package com.Angaliwa
{
	import flash.events.MouseEvent;
	import flash.filters.DropShadowFilter;
	
	import mx.containers.Canvas;
	import mx.containers.ViewStack;
	import mx.controls.TabBar;
	import mx.effects.Move;
	import mx.effects.Resize;
	import mx.effects.easing.Quadratic;
	import mx.events.IndexChangedEvent;
	
	public class Sidebar
	{
		// These items can be customized, if so desired. 
		// You only need to do this if you don't want to
		// use certain modules from Angaliwa. 
		public var settings:Settings = new Settings(this);
		public var daisyChain:DaisyChain = new DaisyChain(this);
		public var resizeHandler:ResizeHandler = Core.g('resizeHandler');
		
		public var sidebarName:String = "Sidebar";
		public var sidebarPanelNameStart:String = "SidebarPanel";
		
		// These items are not to be modified.
		public var coreHandler:String;
		private var parentObject:*;
		
		// Variables related to the sidebar's open/close 
		// functionality
		private var opened:Boolean;
		private var original:Object = [];
		
		// PROTOTYPE variables, make sure we still need them.
		private var container:Canvas = new Canvas();
		private var tabBar:TabBar = new TabBar();
		private var stack:ViewStack = new ViewStack();
		private var panels:Array = new Array();
		
		public var currentActive:String;
		
		/*
		 * Summary:      	Initializes a new sidebar instance. 
		 * Return:       	Sidebar (this)
		 * Version:   	 	1.0
		 * Compatibility:	1.0
		 */
		public function init(parentObject:*, customSettings:Object=undefined):Sidebar{ 
			this.parentObject = parentObject;
			
			this.parentObject.styleName = sidebarName;
			stack.styleName = sidebarName+"ViewStack";
			
			// Set the default settings
			settings.setDefaults({width: 250, height: 500,
								   dockTo: 'right',
								   tabBarLocation: 'top',
								   verticalScrollPolicy:'no', horizontalScrollPolicy:'no',
								   tabBarLocation: 'top', tabBarHeight:30,
								   animateOpenClose:true, easingFunction:Quadratic.easeInOut,
								   openedByDefault:false,animateFirst:false});
			
			// And, if provided, set the custom settings
			if(customSettings)
				settings.add(customSettings);
			
			container.width = settings.get('width');
			container.height= settings.get('height');
			container.verticalScrollPolicy = settings.get('verticalScrollPolicy');
			container.horizontalScrollPolicy = settings.get('horizontalScrollPolicy');
			
			// To make sure the tab bar is always clickable, we'll let the dockTo
			// variable force-update the tabBarLocation, if needed. If no dockTo
			// is provided, the user is free to place the tab bar wherever (s)he
			// likes.
			if(settings.get('dockTo') == "right")
				settings.add({tabBarLocation:'left'});
			else if(settings.get('dockTo') == "left")
				settings.add({tabBarLocation:'right'});
			else if(settings.get('dockTo') == "top")
				settings.add({tabBarLocation:'bottom'});
			else if(settings.get('dockTo') == "bottom")
				settings.add({tabBarLocation:'top'});
			
			// By default, the tab bar is displayed at the top
			tabBar.width = settings.get('width');
			tabBar.height = settings.get('tabBarHeight');
			tabBar.x = 0;
			tabBar.y = 0;
			stack.width = settings.get('width');
			stack.height= settings.get('height')-settings.get('tabBarHeight');
			stack.x = 0;
			stack.y = settings.get('tabBarHeight');
			
			// Shadow test.
			var shadow:DropShadowFilter = new DropShadowFilter(4, 135, 0x000000, 0.9, 7, 7);
			var shadow2:DropShadowFilter= new DropShadowFilter(0, 160, 0x000000, 0.9, 15, 15);
			//tabBar.filters = [shadow];
			stack.filters = [shadow];
			container.filters = [shadow2];
			
			// If any other tab bar location is chosen, we'll make
			// the appropriate changes here.
			switch(settings.get('tabBarLocation')){
				case "bottom":
					tabBar.y = settings.get('height')-settings.get('tabBarHeight');
					stack.y = 0;
				break;
				case "left":
					tabBar.rotation = -90;
					tabBar.width = settings.get('height');
					tabBar.y = settings.get('height');
					stack.width = settings.get('width')-settings.get('tabBarHeight');
					stack.height= settings.get('height');
					stack.x = settings.get('tabBarHeight');
					stack.y = 0;
				break;
				case "right":
					tabBar.rotation = 90;
					tabBar.width = settings.get('height');
					tabBar.x = settings.get('width');
					stack.width = settings.get('width')-settings.get('tabBarHeight');
					stack.height= settings.get('height');
					stack.y = 0;
				break;
			}
			
			// If docking is set, position the sidebar so
			// that it sticks to the specified side.
			switch(settings.get('dockTo')){
				case "left":
					container.x = 0;
					container.y = (parentObject.height/2)-(container.height/2);
					
					//resizeHandler.a(container, ['left','middle'], parentObject);
					resizeHandler.setPosition(container, 'left', 'center');
				break;
				case "right":
					container.x = parentObject.width-container.width;
					container.y = (parentObject.height/2)-(container.height/2);
					
					//resizeHandler.a(container, ['right','middle'], parentObject);
					resizeHandler.setPosition(container, 'right', 'center');
				break;
				case "top":
					container.x = (parentObject.width/2)-(container.width/2);
					container.y = 0;
					
					//resizeHandler.a(container, ['top','hormiddle'], parentObject);
					resizeHandler.setPosition(container, 'center', 'top');
				break;
				default:
				break;
			}
			
			tabBar.dataProvider = stack;
			tabBar.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void{
				if(e.target.label == currentActive)
					toggle(settings.get('animateOpenClose'));
				else{
					open(settings.get('animateOpenClose'));
					currentActive = e.target.label;
				}
			});
			
			// Add the new sidebar to the stage.
			container.addChild(stack);
			container.addChild(tabBar);
			parentObject.addChild(container);
			
			// Check if the sidebar should be closed by default
			if(!settings.get('openedByDefault')){
				var ani:Boolean = settings.get('animateOpenClose');
				if(settings.get('animateFirst') is Boolean) ani=settings.get('animateFirst');
				opened=true;				
				close(ani);
			}
			else opened=true;
			
			stack.addEventListener(IndexChangedEvent.CHANGE, function(e:IndexChangedEvent):void{
				if(panels[e.oldIndex] && panels[e.oldIndex].close is Function)
					panels[e.oldIndex].close();
				
				if(panels[e.newIndex] && panels[e.newIndex].open is Function)
					panels[e.newIndex].open();
			});
			
			return this;
		}
		
		
		/*
		 * Summary:      	Adds a panel to the sidebar. 
		 * Return:       	Sidebar (this)
		 * Version:   	 	1.0
		 * Compatibility:	1.0
		 */
		public function a(panelName:*, panelContent:*=undefined, openFunction:Function=undefined, closeFunction:Function=undefined):Sidebar{
			if(panelName is String){
				var panel:Canvas = new Canvas();
				panel.label = panelName;
				panel.name = panelName;
				
				// DEBUG. We need some vivid colors to see what's 
				// going on here.
				panel.styleName = sidebarPanelNameStart+panelName;
				
				// Add the panel to the resizeHandler.
				//resizeHandler.a(panel, ['full'],container);
				
				panels.push({obj:panel, name:panelName, open:openFunction, close:closeFunction});
				stack.addChild(panel);
				
				if(panels.length == 1)
					currentActive = panelName;
				
				if(panelContent){
					
					// Debug.
					if(panelContent.visible===false)
						panelContent.visible=true;
					
					panel.addChild(panelContent);
				}
				
				//tabBar.dataProvider = stack;
			}
			else{
				for(var i:int=0; i < panelName.length; i++)
					a(panelName[i], panelContent);
			}
			
			return this;
		}
		
		public function g(panelName:String=undefined):*{
			if(panelName){
				for(var i:int=0; i < panels.length; i++){
					if(panels[i].name == panelName)
						return panels[i].obj;
				}
			}
			else return container;
		}
		
		public function toggle(animate:Boolean=true):void{
			if(!opened) open(animate);
				else close(animate);
		}
		
		public function open(animate:Boolean=true):void{
			if(!opened){
				// Open the sidebar
				if(animate){
					var rs:Resize = new Resize(container), 
						mv:Move = new Move(container);
					rs.easingFunction = settings.get('easingFunction');
					mv.easingFunction = settings.get('easingFunction');
					
					switch(settings.get('dockTo')){
						case "right":
							rs.widthFrom = container.width;
							rs.widthTo	 = original.width;
							mv.xFrom = parentObject.width-settings.get('tabBarHeight');
							mv.xTo   = parentObject.width-settings.get('width');
						break;
						case "left":
							rs.widthFrom = container.width;
							rs.widthTo	 = original.width;
							mv.xFrom = 0-(settings.get('width')-settings.get('tabBarHeight'));
							mv.xTo   = 0;
						break;
						case "top":
							mv.yFrom	  = 0-(settings.get('height')-settings.get('tabBarHeight'));
							mv.yTo		  = 0;
						break;
						default:
						break;
					}
					
					rs.play();
					mv.play();
					
					opened=true;
				}
				else{
					switch(settings.get('dockTo')){
						case "right":
							container.width = original.width;
							container.x = parentObject.width-settings.get('width');
						break;
						case "left":
							container.width = original.width;
							container.x = 0;
						break;
						case "top":
							container.y	    = 0;
						break;
						default:
						break;
					}
						
					opened=true;
				}
			}
		}
		
		public function close(animate:Boolean=true):void{
			if(opened){
				original.width = container.width;
				original.height= container.height;
				
				// Close the sidebar
				if(animate){
					var rs:Resize = new Resize(container), 
						mv:Move = new Move(container);
					rs.easingFunction = settings.get('easingFunction');
					mv.easingFunction = settings.get('easingFunction');
					
					switch(settings.get('dockTo')){
						case "right":
							rs.widthFrom = container.width;
							rs.widthTo	 = settings.get('tabBarHeight');
							mv.xFrom	 = parentObject.width-settings.get('width');
							mv.xTo 		 = parentObject.width-settings.get('tabBarHeight');
						break;
						case "left":
							mv.xFrom	 = 0;
							mv.xTo 		 = 0-(settings.get('width')-settings.get('tabBarHeight'));
						break;
						case "top":
							mv.yFrom	  = 0;
							mv.yTo		  = 0-settings.get('height')+settings.get('tabBarHeight');
						break;
						default:
						break;
					}
					
					rs.play();
					mv.play();
					
					opened=false;
				}
				else{
					switch(settings.get('dockTo')){
						case "right":
							container.width = settings.get('tabBarHeight');
							container.x = parentObject.width-settings.get('tabBarHeight');
						break;
						case "left":
							//container.width = settings.get('tabBarHeight');
							container.x = 0-(settings.get('width')-settings.get('tabBarHeight'));
						break;
						case "top":
							container.y = 0-settings.get('height')+settings.get('tabBarHeight');
						break;
						default:
						break;
					}
					
					opened=false;
				}
			}
		}
	}
}